package com.ocean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class DelegateHandle implements InvocationHandler {
	private Class[] bs;

	private DelegateHandle(Class[] bs) {
		this.bs = bs;
	}

	public static Object bind(Class[] as, Class[] bs) {
		return Proxy.newProxyInstance(as[0].getClassLoader(), as,
				new DelegateHandle(bs));
	}

	public static <I> I bind(Class<I> a, Class b) {
		return (I) bind(new Class[] { a }, new Class[] { b });
	}

	public static <I> I bind(Class<I> a, Class[] bs) {
		return (I) bind(new Class[] { a }, bs);
	}

	/*
	 * public static <I> I bind(Class<I>[] a, Class b) { return
	 * (I)Proxy.newProxyInstance(a[0].getClassLoader(), a, new
	 * DelegateHandle(b));//new Class[] }
	 */

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object result = null;
		// System.out.println("A:"+proxy.getClass().getSuperclass().getName());
		// System.out.println("A:"+proxy.getClass().getInterfaces()[0]);
		Method mbegin = null, mimpl = null, mend = null;

		for (int j = 0; j < bs.length; j++) {
			Method[] bms = bs[j].getMethods();
			for (int i = 0; i < bms.length; i++) {
				boolean anflag = bms[i].isAnnotationPresent(Delegate.class);
				if (anflag) {
					Delegate dl = bms[i].getAnnotation(Delegate.class);
					// System.out.println("dl.interfaceName():"+dl.interfaceName());
					Class dlifl = Class.forName(dl.interfaceName());
					if (dlifl.isAssignableFrom(proxy.getClass())
							&& dl.methodName().equals(method.getName())
							&& Arrays.equals(method.getParameterTypes(),
									bms[i].getParameterTypes())
							&& method.getReturnType().equals(
									bms[i].getReturnType())) {
						DelegatePolicy dp = dl.policy();
						if (dp == DelegatePolicy.Begin)
							mbegin = bms[i];
						else if (dp == DelegatePolicy.Implements)
							mimpl = bms[i];
						else if (dp == DelegatePolicy.End)
							mend = bms[i];
					}
				}
			}
		}
		// System.out.println("mimpl111111:"+mimpl);
		if (mimpl != null) {
			if (mbegin != null)
				mbegin.invoke(mbegin.getDeclaringClass().newInstance(), args);
			// System.out.println("11111111:"+mimpl.getDeclaringClass());
			result = mimpl
					.invoke(mimpl.getDeclaringClass().newInstance(), args);
			if (mend != null)
				mend.invoke(mend.getDeclaringClass().newInstance(), args);
		}

		// result = bms[i].invoke(b.newInstance(), args);
		/*
		 * if(method.getName().equals("getStr")) result =
		 * (Object)ClientMain.getStrUtil((String)args[0]); else
		 * if(method.getName().equals("getSomething")) result =
		 * method.invoke(new ClientMain(), args);
		 * //System.out.println("end invoke");
		 */
		return result;
	}

}